package org.wangp.business.user.service

import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.mybatisplus.extension.plugins.pagination.Page
import org.modelmapper.TypeToken
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.data.domain.PageRequest
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.stereotype.Service
import org.wangp.business.user.domain.OrderDTO
import org.wangp.business.user.domain.UserDTO
import org.wangp.business.user.repository.es.UserEsRepo
import org.wangp.business.user.repository.es.domain.UserDoEs
import org.wangp.business.user.repository.remote.IOrderCenter
import org.wangp.business.user.repository.repo.domain.UserDO
import org.wangp.business.user.repository.repo.mapper.UserMapperRepo
import org.wangp.framework.core.domain.CommonResult
import org.wangp.framework.core.exception.BusinessException
import org.wangp.framework.core.util.mapTo
import org.wangp.framework.core.util.mapToType
import java.time.LocalDateTime
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executor
import java.util.regex.Pattern

@Service
class UserService(
	private val userMapperRepo: UserMapperRepo,
	private val userEsRepo: UserEsRepo,
	@Qualifier("asyncThreadPool") private val executor: Executor,
	private val passwordEncoder: PasswordEncoder,
	@Qualifier("IOrderCenter") private val iOrderCenter: IOrderCenter
) {

	private val chinesePattern = Pattern.compile("[\u4e00-\u9fa5]")

	companion object {
		val log: Logger = LoggerFactory.getLogger(UserService::class.java)
	}

	fun searchUser(userDTO: UserDTO): CommonResult<List<UserDTO>> {
		val page = userMapperRepo.selectPage(
			userDTO mapToType object : TypeToken<Page<UserDO>>() {},
			KtQueryWrapper(userDTO mapTo UserDO::class.java)
		)
		return CommonResult.success((page.records mapTo UserDTO::class.java).toList(), page.total)
	}

	fun addUser(userDTO: UserDTO): CommonResult<UserDTO> {
		if (chinesePattern.matcher(userDTO.username!!).find()) {
			throw BusinessException.builder().message("账号不能用中文").build()
		}
		if ((userMapperRepo.selectCount(
				KtQueryWrapper(UserDO::class.java).eq(
					UserDO::username,
					userDTO.username
				)
			) > 0)
		) {
			throw BusinessException.builder().message("用户账号重复").build()
		}
		userDTO.password = passwordEncoder.encode(userDTO.password)
		val userDO = userDTO mapTo UserDO::class.java
		userMapperRepo.insert(userDO)
		userDTO.id = userDO.id
		// 同步添加到es
		CompletableFuture.supplyAsync({
			userEsRepo.save((userDTO mapTo UserDoEs::class.java).apply {
				uid = userDTO.id
				created = LocalDateTime.now()
			})
		}, executor).thenAccept { log.info("sync es result [$it]") }.handle { _, ex -> log.error("sync fail", ex) }
		return CommonResult.success(userDTO)
	}

	fun editUser(userDTO: UserDTO): CommonResult<Void> {
		userMapperRepo.updateById(userDTO mapTo UserDO::class.java)
		return CommonResult.success()
	}

	fun searchUserEs(userDTO: UserDTO): CommonResult<List<UserDTO>> {
		return CommonResult.success(
			(userEsRepo.findByUsername(
				userDTO.username ?: "中",
				pageable = PageRequest.of(userDTO.current.toInt(), userDTO.size.toInt())
			) mapTo UserDTO::class.java).toList(), userEsRepo.count()
		)
	}

	fun searchOrders():List<OrderDTO> {
		return iOrderCenter.getOrdersByUser(userDTO = UserDTO()).data
	}
}
